package com.example.origin.spider.webmagic;

import com.example.origin.spider.properties.ProcessorProperties;
import lombok.Getter;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.downloader.AbstractDownloader;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.PlainText;

import java.io.Closeable;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class SimpleChromeDownloader extends AbstractDownloader implements Closeable {

    @Getter
    private WebDriver webDriver;

    private Logger logger = LoggerFactory.getLogger(getClass());

    private int sleepTime;


    public SimpleChromeDownloader(ProcessorProperties processProperties) {
        String driverPath = processProperties.getDriverPath();
        Boolean showWindow = processProperties.getShowWindow();
        String userAgent = processProperties.getUserAgent();
        this.sleepTime = processProperties.getSleepTime();
        System.setProperty("webdriver.chrome.driver", driverPath);

        ChromeOptions options = new ChromeOptions();

        // 启用隐身模式
        options.addArguments("--incognito");
        // 设置User-Agent
        if (StringUtils.hasText(userAgent)) {
            options.addArguments("user-agent=" + userAgent);
        }
        options.addArguments("--no-sandbox");
        options.addArguments("--disable-dev-shm-usage");
        options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
        options.addArguments("--remote-allow-origins=*");
        // 禁用网页发送通知的弹框
        options.addArguments("--disable-notifications");
        options.addArguments("--disable-infobars");
        // 忽略证书错误
        options.setAcceptInsecureCerts(true);
        // 启动最大化
        options.addArguments("--start-maximized");
        if (!showWindow) {
            // 无头模式，不显示浏览器界面
            options.addArguments("--headless");
            // 禁用GPU加速
            options.addArguments("--disable-gpu");
            // 禁止图像加载，加快加载速度
            options.addArguments("--blink-settings=imagesEnabled=false");

            this.webDriver = new ChromeDriver(options);
        } else {
            this.webDriver = new ChromeDriver(options);
        }
        //ChromeDriver默认的隐式等待时间是0秒
        this.webDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        //默认情况下，这个超时时间是30秒
        this.webDriver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        // 默认超时时间也是30秒
        this.webDriver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
        // 删除所有cookie
        this.webDriver.manage().deleteAllCookies();
    }

    @Override
    public Page download(Request request, Task task) {

        Page page = Page.fail(request);
        try {
            logger.info("downloading page " + request.getUrl());
            webDriver.get(request.getUrl());
            Thread.sleep(sleepTime);
            WebDriver.Options manage = webDriver.manage();
            Site site = task.getSite();
            Map<String, String> cookies = Optional.ofNullable(site.getCookies()).orElse(request.getCookies());
            if (cookies != null) {
                for (Map.Entry<String, String> cookieEntry : cookies.entrySet()) {
                    Cookie cookie = new Cookie(cookieEntry.getKey(), cookieEntry.getValue());
                    manage.addCookie(cookie);
                }
            }

            WebElement webElement = webDriver.findElement(By.xpath("/html"));
            String content = webElement.getAttribute("outerHTML");
            page.setDownloadSuccess(true);
            page.setRawText(content);
            page.setHtml(new Html(content, request.getUrl()));
            page.setUrl(new PlainText(request.getUrl()));
            page.setRequest(request);
            onSuccess(page, task);
        } catch (Exception e) {
            logger.warn("download page {} error", request.getUrl(), e);
            onError(page, task, e);
        }
        return page;
    }

    protected void onSuccess(Page page, Task task) {
        for (Cookie cookie : webDriver.manage().getCookies()) {
            page.getRequest().addCookie(cookie.getName(), cookie.getValue());
            task.getSite().addCookie(cookie.getName(), cookie.getValue());
        }
        super.onSuccess(page.getRequest(), task);
    }


    @Override
    @Deprecated
    public void setThread(int threadNum) {

    }


    @Override
    public void close() {
        if (this.webDriver != null) {
            this.webDriver.manage().deleteAllCookies();
            for (String windowHandle : webDriver.getWindowHandles()) {
                this.webDriver.switchTo().window(windowHandle).close();
            }
            logger.info("Quit webDriver" + webDriver);
            this.webDriver.quit();
            this.webDriver = null;
        }
    }
}
